package com.example.rfb.serviceloader.app_compiler;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;

public class ServiceLoaderAppCompileProcessor extends AbstractProcessor {

    private JavaFileManager mFileManager;
    private Map<String, List<String>> providers = new HashMap<>();

    public ServiceLoaderAppCompileProcessor() {
    }

    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        providers.clear();

        try {
            Field contextField = processingEnvironment.getClass().getDeclaredField("context");
            contextField.setAccessible(true);
            Object context = contextField.get(processingEnvironment);
            Method contextGetMethod = context.getClass().getDeclaredMethod("get", Class.class);
            contextGetMethod.setAccessible(true);
            mFileManager = (JavaFileManager)contextGetMethod.invoke(context, JavaFileManager.class);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | NoSuchFieldException var5) {
            var5.printStackTrace();
        }

    }

    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {

        if (roundEnvironment.processingOver()) {
            return false;
        } else if (((Element)roundEnvironment.getRootElements().iterator().next()).getSimpleName().toString().contains("Provider_")) {
            return false;
        } else {
            String resourceFile = "META-INF/services";

            try {
                HashSet<JavaFileObject.Kind> kinds = new HashSet<>();
                kinds.add(JavaFileObject.Kind.OTHER);
                Iterable<JavaFileObject> locations = mFileManager.list(StandardLocation.CLASS_PATH, resourceFile, kinds, true);
                Iterator<JavaFileObject> iterator = locations.iterator();
                while (iterator.hasNext()){
                    JavaFileObject it = iterator.next();

                    InputStream stream = null;
                    try {
                        log(it.getName());
                        stream = it.openInputStream();
                        Set<String> serviceFile = ServicesFiles.readServiceFile(stream);
                        Iterator var4 = serviceFile.iterator();

                        while(var4.hasNext()) {
                            String impl = (String)var4.next();
                            log(impl);
                            String uriString = it.toUri().toString();

                            String key = uriString.substring(uriString.lastIndexOf("/") + 1);
                            List<String> list = providers.get(key);
                            if(list == null){
                                list = new ArrayList<>();
                                providers.put(key, list);
                            }
                            list.add(impl);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (stream != null) {
                            try {
                                stream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

            if (!providers.isEmpty()) {
                try {
                    ServicePoolGenerator.write(providers, processingEnv);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            return false;
        }
    }

    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    private void log(String msg) {
        if (processingEnv.getOptions().containsKey("debug")) {
            processingEnv.getMessager().printMessage(javax.tools.Diagnostic.Kind.NOTE, msg);
        }

    }

    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new HashSet<>();
        set.add("*");
        return set;
    }
}

